home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume22 / nn6.4 / part07 < prev    next >
Encoding:
Internet Message Format  |  1990-06-07  |  54.4 KB

  1. Subject:  v22i042:  NN Newsreader, release 6.4, Part07/21
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: 39dcb800 39e05c76 44c3ba86 18e5775a
  5.  
  6. Submitted-by: "Kim F. Storm" <storm@texas.dk>
  7. Posting-number: Volume 22, Issue 42
  8. Archive-name: nn6.4/part07
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then feed it
  12. # into a shell via "sh file" or similar.  To overwrite existing files,
  13. # type "sh file -c".
  14. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  15. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  16. # Contents:  man/nn.1.B master.c
  17. # Wrapped by storm@texas.dk on Sun May  6 18:19:31 1990
  18. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  19. echo If this archive is complete, you will see the following message:
  20. echo '          "shar: End of archive 7 (of 22)."'
  21. if test -f 'man/nn.1.B' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'man/nn.1.B'\"
  23. else
  24.   echo shar: Extracting \"'man/nn.1.B'\" \(32572 characters\)
  25.   sed "s/^X//" >'man/nn.1.B' <<'END_OF_FILE'
  26. X.\" BEGINPART B
  27. X.SH FILE NAME EXPANSION
  28. XWhen the save commands prompts for a file name, the following file
  29. Xname expansions are performed on the file name you enter:
  30. X.TP
  31. X\fB+\fP\fIfolder\fP
  32. XThe
  33. X.B +
  34. Xis replaced by the contents of the
  35. X.B folder
  36. Xvariable (default value "~/News/") resulting in the name of a file in the
  37. X.I folder
  38. X.IR directory .
  39. XExamples:
  40. X.br
  41. X    +emacs, +nn, +sources/shar/nn
  42. X.TP
  43. X\fB+\fP
  44. XA single plus is replaced by the expansion of the file name contained in the
  45. X.B default-save-file
  46. Xvariable.
  47. X.TP
  48. X\fB~/\fP\fIfile\fP
  49. XThe
  50. X.B ~
  51. Xis replaced by the contents of the environment variable HOME, i.e. the
  52. Xpath name of your home directory.
  53. XExamples:
  54. X.br
  55. X    ~/News/emacs, ~/News/nn, ~/src/shar/nn
  56. X.TP
  57. X\fB|\fP\fIcommand-line\fP
  58. XInstead of writing to a file, the articles are piped to the given
  59. Xshell (/bin/sh) command-line.  Each save or write command will create a
  60. Xseparate pipe, but all articles saved or written in one command (in
  61. Xselection mode) are given
  62. Xas input to the same shell command.  Example:
  63. X.br
  64. X    | pr | lp
  65. X.br
  66. XThis will print the articles on the printer after they have been piped
  67. Xthrough pr.
  68. X    It is possible to create separate pipes for each saved article by
  69. Xusing a double pipe symbol in the beginning of the command, e.g.
  70. X.br
  71. X    || cd ~/src/nn ; patch
  72. X.br
  73. X.LP
  74. XThe following symbols are expanded in a file name or command:
  75. X.TP
  76. X.B $F
  77. Xwill be expanded to the name of the current group with the periods
  78. Xreplaced by slashes, e.g. rec/music/synth.
  79. X.TP
  80. X.B $G
  81. Xwill be expanded to the name of the current group.
  82. X.TP
  83. X.B $L
  84. Xwill be expanded to the \fIlast component\fP of the name of the
  85. Xcurrent group.  You may use this to create default save file names
  86. Xlike +src/$L in the comp.sources groups.
  87. X.TP
  88. X.B $N
  89. Xwill be expanded to the (local) article number, e.g. 1099.  In
  90. Xselection mode it is only allowed at the end of the file name!
  91. X.TP
  92. X.B $(VAR)
  93. Xis replaced by the string value of the environment variable \fIVAR\fP.
  94. X.LP
  95. XUsing these symbols, a simple naming scheme for `default folder name' is
  96. X.B +$G
  97. Xwhich will use the group name as folder name.  Another possibility is
  98. X.BR +$F/$N .
  99. X.LP
  100. XAs mentioned above, you can also instruct \fInn\fP to save a series of
  101. Xfiles in separate, unique files.  All that is required is that the
  102. Xfile name contains an asterisk, e.g.
  103. X.br
  104. X    +src/hype/part*.shar
  105. X.br
  106. XThis will cause each of the articles to be saved in separate, unique
  107. Xfiles named part1.shar, part2.shar, and so on, always choosing a part
  108. Xnumber that results in a unique file name (i.e. if part1.shar did
  109. Xalready exist, the first article would be saved in part2.shar, the
  110. Xnext in part3.shar, and so on).
  111. X.LP
  112. X\fBRelated variables\fP:
  113. Xdefault-save-file, folder, save-counter, save-counter-offset.
  114. X.SH FILE AND GROUP NAME COMPLETION
  115. XWhen entering a file name or a news group name, a simple
  116. X.B completion
  117. Xfeature is available using the \fBspace\fP, \fBtab\fP, and \fB?\fP keys.
  118. X.LP
  119. XHitting \fBspace\fP anywhere during input will complete the
  120. X.I current
  121. X.I component
  122. Xof the file name or group name with the
  123. X.I first
  124. Xavailable possibility.
  125. X.LP
  126. XIf this possibility is not the one you want, keep on hitting
  127. X.B space
  128. Xuntil it appears.
  129. X.LP
  130. XWhen the right completion has appeared, you can just continue typing
  131. Xthe file or group name, or you can hit
  132. X.B tab
  133. Xto fix the current component, and get the
  134. X.I first
  135. Xpossibility for the next component, and then use
  136. X.B space
  137. Xto go through the other possible completions.
  138. X.LP
  139. XThe
  140. X.B ?
  141. Xkey will produce a list of the possible
  142. X.I completions
  143. Xof the current component.  If the list is too long for the available
  144. Xspace on screen, the key can be repeated to get the next part of the
  145. Xlist.
  146. X.LP
  147. XThe current completion can be deleted with the
  148. X.B erase
  149. Xkey.
  150. X.LP
  151. XThe default value for a file name is the last file name you have
  152. Xentered, so if you enter a
  153. X.B space
  154. Xas the first character after the prompt, the last file name will be
  155. Xrepeated (and you can edit it if you like).  In some cases, a string
  156. Xwill already be written for you in the prompt line, and to get the
  157. Xdefault value in these cases, use the \fBkill\fP key.  This also means
  158. Xthat if you neither want the initial value, nor the default value, you
  159. Xwill have to hit the \fBkill\fP twice to get a clean prompt line.
  160. X.LP
  161. X\fBRelated variables\fP:
  162. Xcomp1-key, comp2-key, help-key, suggest-default-save.
  163. X.SH POSTING AND RESPONDING TO ARTICLES
  164. XIn both selection mode and reading mode you can post new articles,
  165. Xpost follow-ups to articles, send replies to the author of an article,
  166. Xand you can send mail to another user with the option of including an
  167. Xarticle in the letter.  In reading mode, a response is made to the
  168. Xcurrent article, while in selection mode you will be prompted for an
  169. Xarticle to respond to.
  170. X.LP
  171. XThe following commands are available (the lower-case equivalents are
  172. Xalso available in reading mode):
  173. X.TP
  174. X\&\fBR\fP    {\fBreply\fP}
  175. XReply through mail to the author of the article.  This is the prefered
  176. Xway to respond to an article unless you think your reply is of general
  177. Xinterest.
  178. X.TP
  179. X\&\fBF\fP    {\fBfollow\fP}
  180. XFollow-up with an article in the same newsgroup (unless an alternative
  181. Xgroup is specified in the article header).
  182. X.TP
  183. X\&\fBM\fP    {\fBmail\fP}
  184. XMail a letter or
  185. X.I forward
  186. Xan article to a single recipient.
  187. XIn selection mode, you will be prompted for an article to include
  188. Xin your letter, and in reading mode you will be asked if the current
  189. Xarticle should be included in the letter.
  190. XYou will then be prompted for the recipient of the letter (default
  191. Xrecipient is yourself)
  192. Xand the subject of the letter (if an article is included, you may hit
  193. X.B space
  194. Xto get the default subject which is the subject of the included article).
  195. X  The header of the article is only included in the posted letter if
  196. Xit is forwarded (i.e. not edited), or if the variable
  197. X\fBinclude-full-header\fP is set.
  198. X.TP
  199. X\&\fB:post\fP    {\fBpost\fP}
  200. XPost a new article to any newsgroup.  This command will prompt you for
  201. Xa
  202. X.I comma-separated
  203. Xlist of newsgroups to post to (you cannot enter a space because
  204. X.B space
  205. Xis used for group name completion as described below).
  206. X.LP
  207. XGenerally, \fInn\fP will construct a file with a suitable header, optionally
  208. Xinclude a copy of the article in the file with each non-empty line
  209. Xprefixed by a `>' character (except in mail mode), and invoke an
  210. Xeditor of your choice (using the EDITOR environment variable) on this
  211. Xfile, positioning you on the first line of the body of the article (if
  212. Xit knows the editor).
  213. X.PP
  214. XWhen you have completed editing the message, it will compare it to the
  215. Xunedited file, and if they are identical (i.e. you did not make any
  216. Xchanges to the file), or it is empty, the operation is cancelled.
  217. XOtherwise you will be prompted for an action to take on the
  218. Xconstructed article (enter first letter followed by \fBreturn\fP, or
  219. Xjust \fBreturn\fP to take the default action):
  220. X.br
  221. X.sp 0.5v
  222. X    Action: a)bort e)dit i)spell r)eedit s)end v)iew w)rite  (send)
  223. X.sp 0.5v
  224. X.br
  225. XYou now have the opportunity to perform one of the following actions:
  226. X.LP
  227. X.in +2m
  228. X.ta 5m
  229. X.\"ta 4 9
  230. X\fBa\fP    throw the response away (will ask for confirmation),
  231. X.br
  232. X\fBe\fP    edit the file again,
  233. X.br
  234. X\fBi\fP    run an (interactive) \fBspell-checker\fP on the text,
  235. X.br
  236. X\fBr\fP    throw away the edited text and edit the original text,
  237. X.br
  238. X\fBs\fP    send the article or letter,
  239. X.br
  240. X\fBv\fP    view the article (through the \fBpager\fP), or
  241. X.br
  242. X\fBw\fP    append it to a file (before you send it).
  243. X.in -2m
  244. X.DT
  245. X.LP
  246. X\fBRelated variables\fP:
  247. Xappend-signature-mail, append-signature-post, default-distribution,
  248. Xedit-response-check, editor, include-art-id, include-full-header,
  249. Xincluded-mark, mail-header, mail-record, mail-script, mailer,
  250. Xmailer-pipe-input, news-header, news-record, news-script,
  251. Xorig-to-include-mask, pager, query-signature,
  252. Xrecord, response-check-pause, response-default-answer,
  253. Xsave-counter, save-counter-offset, save-report, spell-checker.
  254. X.SH JUMPING TO OTHER GROUPS
  255. XBy default \fInn\fP will present the news groups in a predefined
  256. Xsequence (see the section on Presentation Sequence later on).
  257. XTo override this sequence and have a look at any other group the
  258. X.B G
  259. X{\fBgoto-group\fP} command available in both selection and reading
  260. Xmode enables you to move freely between all the newsgroups.
  261. X.LP
  262. XFurthermore, the
  263. X.B G
  264. Xcommand enables you to open folders and other files, to read old
  265. Xarticles you have read before, and to grep for a specific subject in a
  266. Xgroup.
  267. X.PP
  268. XIt is important to notice that normally the goto command is recursive,
  269. Xi.e. a new \fImenu level\fP is created when the specified group or
  270. Xfolder is presented, and when it has been read, \fInn\fP will continue
  271. Xthe activity in the group that was presented before the goto command
  272. Xwas executed.  However, if there are unread articles in the target
  273. Xgroup you can avoid entering a new menu level by using the
  274. X.B j
  275. Xreply described below.  The current menu level (i.e. number of nested
  276. Xgoto commands) will be shown in the prompt line as "<N>" (in reverse
  277. Xvideo).
  278. X.PP
  279. XThe goto command is very powerful, but unfortunately also a little bit
  280. Xtricky at first sight, because the facilities it provides depend on
  281. Xthe context in which the command is used.
  282. X.PP
  283. XWhen executed, the goto command will prompt you for the name of the
  284. Xnewsgroup, folder, or file to open.  It will use the first letter
  285. Xyou enter to distinguish these three possibilities:
  286. X.TP
  287. X.B return
  288. XAn empty answer is equivalent to the current newsgroup.
  289. X.TP
  290. X\fIletter\fP
  291. XThe answer is taken to be the name of a newsgroup.
  292. X.TP
  293. X.I +
  294. X.br
  295. XThe answer is taken to be the name of a folder.  If only `+' is
  296. Xentered, it is equivalent to the default save file for the current
  297. Xgroup.
  298. X.TP
  299. X\fI\&/ or ./ or ~/\fP
  300. XThe answer is taken to be the name of a file, either relative to the
  301. Xcurrent directory, relative to your home directory, or an absolute
  302. Xpath name for the file.
  303. X.TP
  304. X.B %
  305. XIn reading mode, this reply corresponds to reading the current article
  306. X(and splitting it as a digest).  In selection mode, it will prompt for
  307. Xan article on the menu to read.
  308. X.TP
  309. X.B @
  310. XThis choice is equivalent to the archive file for the current group.
  311. X\fInnmaster\fP maintains archive files with all old and current
  312. Xarticles for the groups which have the auto-archive option set in the
  313. XGROUPS file (see \fInnmaster\fP(8)).
  314. X.TP
  315. X\fB=\fP and \fInumber\fP
  316. XThese answers are equivalent to the same answers described below
  317. Xapplied to the current group (e.g. \fBG return =\fP and \fBG =\fP are
  318. Xquivalent).
  319. X.LP
  320. XSpecifying a folder, a file, or an article (with \fB%\fP) will cause
  321. X\fInn\fP to treat the file like a digest and split it into separate
  322. Xarticles (not physically!)  which are then presented on a menu in the
  323. Xusual way, allowing you to read or save individual subarticles from
  324. Xthe folder.
  325. X.LP
  326. XWhen you enter a group name, \fInn\fP will ask you how many articles
  327. Xin the group you want to see on the menu.  You can give the following
  328. Xanswers:
  329. X.TP
  330. X.I a number N
  331. XIn this case you will get the newest N articles in the group, or if
  332. Xyou specified the current group (by hitting \fBreturn\fP to the group
  333. Xname prompt or entering the number directly), you will get that many
  334. X\fIextra\fP articles included on the same menu (without creating a new
  335. Xmenu level).
  336. X.TP
  337. X.B j
  338. XThis answer can only be given if there are unread articles in the
  339. Xgroup.  It will instruct nn to jump directly to the specified group in
  340. Xthe presentation sequence \fIwithout\fP creating a new menu level.
  341. X.TP
  342. X.B u
  343. XThis instructs \fInn\fP to present the \fIunread\fP articles in the
  344. Xgroup (if there are any).  If you have already read the group (in the
  345. Xcurrent invocation of \fInn\fP), the \fBu\fP answer will instruct
  346. X\fInn\fP to present the articles that were unread when you entered
  347. X\fInn\fP.
  348. X.TP
  349. X.B a
  350. XThis instruct \fInn\fP to present \fBall\fP articles in the group.
  351. X.TP
  352. X\fBs\fP\fIword\fP or \fB=\fP\fIword\fP
  353. XThis instructs \fInn\fP to search \fIall\fP articles in the groups,
  354. Xbut only present the articles containing the word \fIword\fP in the
  355. Xsubject.  Notice that case is ignored when searching for the word in
  356. Xthe subject lines.
  357. X.TP
  358. X\fBn\fP\fIword\fP
  359. XSame as the \fBs\fP form except that it searched for articles where
  360. Xthe sender \fIname\fP matches \fIword\fP.
  361. X.TP
  362. X\fBe\fP\fIword\fP
  363. XSame as the \fBs\fP form except that it Psearched for articles where
  364. X\fIeither\fP the subject or the sender name matches \fIword\fP.
  365. X.TP
  366. X\fIword\fP = \fB/\fP\fIregexp\fP
  367. XWhen the first character of the \fIword\fP specified with the \fBs\fP,
  368. X\fBn\fP, and \fBe\fP forms is a slash `/', the rest of the input is
  369. Xinterpreted as a regular expression to search for.  Notice that
  370. Xregular expression matching is case insensitive when
  371. X\fBcase-fold-search\fP is set (default).
  372. X.TP
  373. X.B return
  374. XThe meaning of an empty answer depends on the context: if there are
  375. Xunread articles in the specified group the unread articles will be
  376. Xpresented, otherwise \fIall\fP articles in the group will be included
  377. Xin the menu.
  378. X.LP
  379. XIf you specified the current group, and the menu already contains all
  380. Xthe available articles, \fInn\fP will directly prompt for a word to
  381. Xsearch for in the subject of all articles (the prompt will be an equal
  382. Xsign.)
  383. X.LP
  384. XWhen the goto command creates a new menu level, \fInn\fP will not
  385. Xperform auto kill or selection in the group.  You can use the \fB+\fP
  386. Xcommand in menu mode to perform the auto-selections.
  387. X.LP
  388. XThere are three commands in the goto family:
  389. X.TP
  390. X\&\fBG\fP    {\fBgoto-group\fP}
  391. XThis is the general goto command described above.
  392. X.TP
  393. X\&\fBB\fP    {\fBback-group\fP}
  394. XBackup one or more groups.  You can hit this key one or more times to
  395. Xgo back in the groups already presented (including those without new
  396. Xarticles); when you have found the group you are looking for, hit
  397. X\fBspace\fP to enter it.
  398. X.TP
  399. X\&\fBA\fP    {\fBadvance-group\fP}
  400. XAdvance one or more groups.  This command is similar to the \fBB\fP
  401. Xcommand, but operates in the opposite direction.
  402. X.TP
  403. X\&\fBN\fP    {\fBnext-group\fP}
  404. XWhen used within an \fBA\fP or \fBB\fP command, it skips forward to
  405. Xthe next group in the sequence with unread articles or which has
  406. Xpreviously been visited.
  407. X.TP
  408. X\&\fBP\fP    {\fBprevious\fP}
  409. XWhen used within an \fBA\fP or \fBB\fP command, it skips backwards to
  410. Xthe preceding group in the sequence with unread articles or which has
  411. Xpreviously been visited.
  412. X.LP
  413. XOnce you have entered an \fBA\fP or \fBB\fPcommand, you can freely mix
  414. Xthe \fBA\fP, \fBB\fP, \fBP\fP, and \fBN\fP commands to find the group
  415. Xyou want, and you can also use the \fBG\fP command to be prompted for
  416. Xa group name.
  417. X.LP
  418. XTo show the use of the goto command some typical examples on
  419. Xits use are given below:
  420. X.sp
  421. X.nf
  422. X.I "Present the unread articles in the dk.general group"
  423. X.sp 0.5v
  424. X     \fBG\fP dk.general \fBreturn\fP \fBu\fP
  425. X.sp
  426. X.I "Jump directly to the gnu.emacs group and continue from there"
  427. X.sp 0.5v
  428. X     \fBG\fP gnu.emacs \fBreturn\fP \fBj\fP
  429. X.sp
  430. X.I "Include the last 10 READ articles in the current group menu"
  431. X.sp 0.5v
  432. X     \fBG\fP 10 \fBreturn\fP
  433. X.sp
  434. X.I "Find all articles in rec.music.misc on the subject Floyd"
  435. X.sp 0.5v
  436. X     \fBG\fP rec.music.misc \fBreturn\fP
  437. X     \fB=\fP floyd \fBreturn\fP
  438. X.sp 0.5v
  439. X.sp
  440. X.I "Open the folder +nn"
  441. X.sp 0.5v
  442. X     \fBG\fP +nn \fBreturn\fP
  443. X.sp
  444. X.I "Split current article as a digest (in reading mode)"
  445. X.sp 0.5v
  446. X     \fBG\fP \fB%\fP
  447. X
  448. X.fi
  449. X.LP
  450. X\fBRelated variables\fP:
  451. Xcase-fold-search, default-save-file
  452. X.SH AUTOMATIC KILL AND SELECTION
  453. XWhen there is a subject or an author which you are either very
  454. Xinterested in, or find completely uninteresting, you can easily
  455. Xinstruct \fInn\fP to \fIauto-select\fP or \fIauto-kill\fP articles
  456. Xwith specific subjects or from specific authors.  These instructions
  457. Xare stored in a \fIkill file\fP, and the most common types of entries
  458. Xcan be created using the following command:
  459. X.TP
  460. X\&\fBK\fP    {\fBkill-select\fP}
  461. XCreate an entry in your personal kill file.  The contents of the entry
  462. Xis specified during a short dialog that is described in details below.
  463. XThis command is available in both selection and reading mode.
  464. X.LP
  465. XEntries in the kill file may apply to a single newsgroup or to all
  466. Xnewsgroups.  Furthermore, entries may be permanent or they may be
  467. Xexpired a given number of days after their entry.
  468. X.LP
  469. XTo increase performance, \fInn\fP uses a compiled version of the kill
  470. Xfile which is read in when \fInn\fP is invoked.  The compiled kill
  471. Xfile will automatically be updated if the normal kill file has been
  472. Xmodified.
  473. X.LP
  474. XThe following dialog is used to build the kill file entry:
  475. X.TP
  476. X\fIAUTO (k)ill or (s)elect (CR => Kill subject 1 month)\fP
  477. XIf you simply want \fInn\fP to kill all articles with the subject of
  478. Xthe current article (in reading mode) or a specific article (which
  479. X\fInn\fP will prompt for in selection mode), just hit \fBreturn\fP.
  480. XThis will cause \fInn\fP to create an entry in the kill file to kill
  481. Xthe current (or specified) subject in the current group for a period
  482. Xof 30 days (which should be enough for the discussion to die out).
  483. X.sp 0.5v
  484. XIf this "default behaviour" is not what you want, just answer either
  485. X\fIk\fP or \fIs\fP to kill or select articles, respectively, which
  486. Xwill bring you on to the rest of the questions.
  487. X.TP
  488. X\fIAUTO SELECT on (s)ubject or (n)ame  (s)\fP
  489. X(The \fISELECT\fP will be substituted with \fIKILL\fP depending on the
  490. Xprevious answer).  Here you specify whether you want the kill or
  491. Xselect to depend on the subject of the article (\fBs\fP or
  492. X\fBspace\fP), or on the name of the author (\fBn\fP).
  493. X.TP
  494. X\fISELECT NAME:\fP
  495. X(Again \fISELECT\fP may be substituted with \fIKILL\fP and
  496. X\fISUBJECT\fP may replace \fINAME\fP).  You must now enter a name (or
  497. Xsubject) to select (or kill).  In reading mode, you may just hit
  498. X\fBreturn\fP (or \fB%\fP) to use the name (or subject) of the current
  499. Xarticle.  In selection mode, you can use the name (or subject) from an
  500. Xarticle on the menu by answering with \fB%\fP followed by the
  501. Xcorresponding article identifier.
  502. X.sp 0.5v
  503. XWhen the name or subject is taken from an article (the current or one
  504. Xfrom the menu), \fInn\fP will only select or kill articles where the
  505. Xname or subject matches the original name or subject exactly including
  506. Xcase.
  507. X.sp 0.5v
  508. XIf the first character typed at the prompt is a slash `/', the rest of
  509. Xthe line is used as a \fIregular expression\fP which is used to match
  510. Xthe name or subject (case \fIin\fPsensitive).
  511. X.sp 0.5v
  512. XOtherwise, \fInn\fP will select or kill articles which \fIcontain\fP
  513. Xthe specified string anywhere in the name or subject (ignoring case).
  514. X.TP
  515. X\fISELECT in (g)roup `dk.general' or in (a)ll groups  (g)\fP
  516. XYou must now specify whether the selection or kill should apply to the
  517. Xcurrent group only (\fBg\fP or \fBspace\fP) or to all groups (\fBa\fP).
  518. X.TP
  519. X\fILifetime of entry in days (p)ermanent  (30)\fP
  520. XYou can now specify the lifetime of the entry, either by entering a
  521. Xnumber specifying the number of days the entry should be active, or
  522. X\fBp\fP to specify the entry as a permanent entry.  An empty reply is
  523. Xequivalent to 30 days.
  524. X.TP
  525. X\fICONFIRM SELECT ....\fP
  526. XFinally, you will be asked to confirm the entry, and you should
  527. Xespecially note the presence or absence of the word \fBexact\fP which
  528. Xspecify whether an exact match applies for the entry.
  529. X.LP
  530. X\fBRelated variables\fP:
  531. Xkill.
  532. X.SH THE FORMAT OF THE KILL FILE
  533. XThe kill file consists of one line for each entry.  Empty lines and
  534. Xlines starting with a # character are ignored.  \fInn\fP automatically
  535. Xplaces a # character in the first position of expired entries when it
  536. Xcompiles the kill file.  You can then edit the kill file manually from
  537. Xtime to time to clean out these entries.
  538. X.LP
  539. XEach line has the following format
  540. X.br
  541. X  [\fIexpire time\fP :] [\fIgroup name\fP] : \fIflags\fP : \fIstring\fP [: \fIstring\fP]...
  542. X.br
  543. X.LP
  544. XPermanent entries have no \fIexpire time\fP (in which case the colon
  545. Xis omitted as well!).  Otherwise, the \fIexpire time\fP defines the
  546. Xtime (as a time_t value) when the entry should be expired.
  547. X.LP
  548. XThe \fIgroup name\fP field can have three forms:
  549. X.TP
  550. X\fInews.group.name\fP
  551. XIf it is the name of a single news group (e.g. comp.unix), 
  552. Xthe entry applies to that group only.
  553. X.TP
  554. X\fB/\fP\fIregular expression\fP
  555. XIf it starts with a slash `/' followed by a \fIregular expression\fP
  556. X(e.g. /^news\e..*), the entry applies to all groups whose name are
  557. Xmatched by the regular expression.
  558. X.TP
  559. X\fIempty\fP
  560. XAn empty group field will apply the entry to \fIall\fP groups.
  561. X.LP
  562. XThe \fIflags\fP field consists of a list of characters which
  563. Xidentifies the type of entry, and the interpretation of each
  564. X\fIstring\fP field.  When used, the flag characters must be used in
  565. Xthe order in which they are desctibed below:
  566. X.TP
  567. X\fB~\fP    (optional)
  568. X.br
  569. XWhen this flag is present on any of the entries for a specific group,
  570. Xit causes all entires which \fIare not auto-selected\fP to be killed.
  571. XThis is a simple way to say: I'm interested in this and that, but
  572. Xnothing else.
  573. X.TP
  574. X\fB+\fP    or \fB!\fP (optional)
  575. X.br
  576. XSpecify an auto-select \fB+\fP or an auto-kill \fB!\fP entry,
  577. Xrespectively.  If neither are used, the article is neither selected
  578. Xnor killed which is useful in combination with the `\fB~\fP' flag.
  579. X.LP
  580. XFor each \fIstring\fP, the \fIflags\fP field must contain the following
  581. Xcharacters defining the interpretation of the corresponding
  582. X\fIstring\fP:
  583. X.TP
  584. X\fBn\fP or \fBs\fP (mandatory)
  585. X.br
  586. XSpecify whether the corresponding string applies to the name \fBn\fP
  587. Xor to the subject \fBs\fP of an article.
  588. X.TP
  589. X\fB/\fP (optional)
  590. X.br
  591. XSpecifies that the corresponding \fIstring\fP is a \fBregular expression\fP
  592. Xwhich the sender or subject is matched against.  If not specified, a simple
  593. Xstring match is performed using the given \fIstring\fP.
  594. X.TP
  595. X\fB=\fP (optional)
  596. X.br
  597. XSpecifies that the match against the name or subject is \fIcase
  598. Xsensitive\fP.  Furthermore, when regular expression matching
  599. Xis \fInot\fP used, the name or subject must be of the same length
  600. Xof the \fIstring\fP to match.
  601. XOtherwise, the match will be case insensitive, and a \fIstring\fP may
  602. Xoccur anywhere in the name or subject to match.
  603. X.TP
  604. X\fB|\fP or \fB&\fP (mandatory if multiple strings)
  605. X.br
  606. XIf more than one string is specified, the set of \fIflags\fP
  607. Xcorresponding to each \fIstring\fP must be separated by either an
  608. X\fIor operator\fP `\fB|\fP' or an \fIand operator\fP `\fB&\fP'.  The
  609. Xand operator has a higher precedence than the or operator, e.g.  a
  610. Xcomplex match expression \fIa|b&c|d\fP will succeed if either of
  611. X\fIa\fP, \fIb&c\fP, or \fId\fP matches.
  612. X.LP
  613. XThe \fIstring\fP field in the entry is the name, subject or regular
  614. Xexpression that will be matched against the name or subject of each
  615. Xarticle in the group (or all groups).  Colons and backslashes must be
  616. Xescaped with a backslash in the string.
  617. X.LP
  618. XExample 1:  Auto-select articles from `Tom Collins' (exact) on subject
  619. X`News' in all groups:
  620. X.sp 0.5v
  621. X    :+n=&s:Tom Collins:News
  622. X.sp
  623. XExample 2:  Kill all articles which are neither from `Tom' or `Eve' in
  624. Xsome.group.  Select only articles from Eve:
  625. X.sp 0.5v
  626. X    some.group:~n:Tom
  627. X.br
  628. X    some.group:+n:Eve
  629. X.sp
  630. XThe second example can also be written as a single entry with an or
  631. Xoperator (in this case, the select/kill attribute only applies to the succeeding strings):
  632. X.br
  633. X    some.group:~n|+n:Tom:Eve
  634. X.LP
  635. XTo remove expired entries, to "undo" a \fBK\fP command, and to make
  636. Xthe more advanced entries with more than one string, you will have to
  637. Xedit the kill file manually.  To recompile the file, you can use the
  638. X\fB:compile\fP command.  When you invoke \fInn\fP, it will also
  639. Xrecompile the kill file if the compiled version is out of dat.
  640. X.SH SHELL ESCAPES
  641. XThe
  642. X.B !
  643. Xcommands available in selection and reading mode are identical in
  644. Xoperation (with one exception).  When you enter the shell escape
  645. Xcommand, you will be prompted for a shell command.  This command will
  646. Xbe fed to the shell specified in the \fBshell\fP variable (default
  647. Xloaded from the SHELL environment variable or /bin/sh) after the
  648. Xfollowing substitutions have been performed on the command:
  649. X.TP
  650. X\fIFile name expansion\fP
  651. XThe ealier described file name expansions will be performed on all
  652. Xarguments.
  653. X.TP
  654. X.B $G
  655. Xwill be substituted with the name of the current news group.
  656. X.TP
  657. X.B $L
  658. Xwill be substituted with the \fIlast component\fP of the name of the
  659. Xcurrent news group.
  660. X.TP
  661. X.B $F
  662. Xwill be substituted with the name of the current news group with the
  663. Xperiods replaced by slashes.
  664. X.TP
  665. X.B $N
  666. Xwill be substituted with the (local) article number (only defined in
  667. Xreading mode).
  668. X.TP
  669. X.B $A
  670. Xis replaced by the full path name of the file containing the current article
  671. X(only defined in reading mode).
  672. X.TP
  673. X.B %
  674. XSame as $A.
  675. X.TP
  676. X.B $(VAR)
  677. Xis replaced by the string value of the environment variable \fIVAR\fP.
  678. X.LP
  679. XWhen the shell command is completed, you will be asked to hit any key
  680. Xto continue.  If you hit the
  681. X.B !
  682. Xkey again, you will be prompted for a new shell command.  Any other
  683. Xkey will redraw the screen and return you to the mode you came from.
  684. X.LP
  685. X\fBRelated variables\fP:
  686. Xshell, shell-restrictions.
  687. X.SH MISCELLANEOUS COMMANDS
  688. XBelow are more useful commands which are available in both
  689. Xselection and reading modes.
  690. X.TP
  691. X\&\fBU\fP    {\fBunsub\fP}
  692. XUnsubscribe to the current group.  You will not see this group
  693. Xanymore unless you explicitly request it.  If the variable
  694. X\fBunsubscribe-mark-read\fP is set, all articles in the group will be
  695. Xmarked read when you unsubscribe.
  696. X  If the variable \fBkeep-unsubscribed\fP is not set, the group will
  697. Xbe removed from .newsrc.  If you are not subscribing to the group, you
  698. Xwill be given the possibility to \fIresubscribe\fP to the group!  This
  699. Xmay be used in connection with the \fBG\fP command to resubscribe a
  700. Xgroup.
  701. X.TP
  702. X\&\fBC\fP    {\fBcancel\fP}
  703. XCancel (delete) an article in the current group or folder.  Cancelling
  704. Xarticles in a folder will cause the folder to be rewritten when it is
  705. Xclosed.  In selection mode, you will be prompted for the identifier of
  706. Xthe article to cancel.  Normal users can only cancel their own
  707. Xarticles.
  708. X.TP
  709. X\&\fBY\fP    {\fBoverview\fP}
  710. XProvide an overview of the groups with unread articles.
  711. X.TP
  712. X\&\fB"\fP    {\fBlayout\fP}
  713. XChange menu layout in selection mode.  The menu will be redrawn using
  714. Xthe next layout (cycling through ..., 2, 3, 4, 0, 1, ...)
  715. X.LP
  716. XMost of the commands in \fInn\fP are bound to a key and can be activated
  717. Xby a single keystroke.  However, there are a few commands that
  718. Xcannot be bound to a key directly.
  719. X.LP
  720. XAs shown in the keystroke command descriptions, all commands have a
  721. Xname, and it is possible to activate a command by name with the
  722. X\fIextended command\fP key (\fB:\fP).  Hitting this key will prompt
  723. Xyou for the name of a command (and parameters).  For example, an
  724. Xalternative to hitting the \fBR\fP key to reply to an article is to
  725. Xenter the extended command \fB:reply\fP followed by \fBreturn\fP.  The
  726. X\fB:post\fP and \fB:unshar\fP commands described earlier can also be
  727. Xbound to a key.  The complete list of commands which can be bound to
  728. Xkeys is provided in the section on Key Mappings below.
  729. X.LP
  730. XThe following extended commands \fIcannot\fP be bound to a key, mainly
  731. Xbecause they require additional parameters on the prompt line, or
  732. Xbecause it should not be possible to activate them too easily.
  733. X.TP
  734. X\fB:admin\fP
  735. XEnter administrative mode.  This is identical in operation to the
  736. X.IR nnadmin (1M)
  737. Xprogram.
  738. X.TP
  739. X\fB:bug\fP
  740. XPrepare and send a bug report to the nn-bugs mailing address.
  741. X.TP
  742. X\fB:cd\fP [ \fIdirectory\fP ]
  743. XChange current working directory.  If the directory argument is not provided,
  744. X\fInn\fP will prompt for it.
  745. X.TP
  746. X\fB:compile\fP
  747. XRecompile the \fIkill\fP file.  This is not necessary under normal
  748. Xoperation since \fInn\fP automatically compiles the file on start-up
  749. Xif it has changed, but it can be used if you modify the kill file
  750. Xwhile \fInn\fP is suspended.
  751. X.TP
  752. X\fB:coredump\fP
  753. XAbort with a core dump.  For debugging purposes only.
  754. X.TP
  755. X\fB:define\fP \fImacro\fP
  756. XDefine macro number \fImacro\fP as described in the Macro Definition
  757. Xsection below.  If \fImacro\fP is omitted, the next free macro number
  758. Xwill be chosen.
  759. X.TP
  760. X\fB:dump\fP \fItable\fP
  761. XSame as the \fB:show\fP command described below.
  762. X.TP
  763. X\fB:help\fP [ \fIsubject\fP ]
  764. XProvide online help on the specified subject.  If you omit the
  765. Xsubject, a list of the available topics will be given.
  766. X.TP
  767. X\fB:local\fP \fIvariable\fP [ \fIvalue\fP ]
  768. XMake the variable local to the current group.  Subsequent changes to
  769. Xthe variable will only be effective until the current group is left.
  770. XIf a value is specified, it will be assigned to the local variable.
  771. XTo assign a new value to a boolean variable, the values \fBon\fP and
  772. X\fBoff\fP must be used.
  773. X.TP
  774. X\fB:man\fP
  775. XCall up the online manual.  The manual is presented as a normal folder
  776. Xwith the program name in the `From' field and the section title in the
  777. X\&`subject' field.  All the normal commands related to a folder works
  778. Xfor the online manual as well, e.g. you can save and print sections of
  779. Xthe manual.
  780. X.TP
  781. X\fB:map\fP \fIarguments\fP
  782. XThis is the command used for binding commands to the keys.  It is
  783. Xfully described in the Key Mapping section below.
  784. X.TP
  785. X\fB:mkdir\fP [ \fIdirectory\fP ]
  786. XCreate the directory (and the directories in its path).  It will
  787. Xprompt for at directory name if the argument is omitted.
  788. X.TP
  789. X\fB:pwd\fP
  790. XPrint path name of current working directory on message line.
  791. X.TP
  792. X\fB:q\fP
  793. XHas no effect besides redrawing the screen if necessary.  If an
  794. Xextended command (one which is prefixed by a :) produces any output
  795. Xrequirering the screen to be redrawn, the screen will not be redrawn
  796. Ximmediately if the variable \fBdelayed-redraw\fP is set (useful on
  797. Xslow terminals).  Instead another \fB:\fP prompt is shown to allow you
  798. Xto enter a new extended command immediately.  It is sufficient to hit
  799. X.B return
  800. Xto redraw the screen, but it has been my experience that entering
  801. X.B q return
  802. Xin this situation happens quite often, so it was made a no-op.
  803. X.TP
  804. X\fB:q!\fP
  805. XQuit \fInn\fP without updating the \fB.newsrc\fP file.
  806. X.TP
  807. X\fB:Q\fP
  808. XQuit \fInn\fP.  This is equivalent to the normal
  809. X.B Q
  810. Xcommand.
  811. X.TP
  812. X\fB:rmail\fP
  813. XOpen your mailbox (see the \fBmail\fP variable) as a folder to
  814. Xread the incoming messages.  This is \fInot\fP a full mail interface
  815. X(you cannot delete messages, no cc: on replies, etc), but it can give
  816. Xyou a quick glance at new mail without leaving \fInn\fP.
  817. X.TP
  818. X\fB:set\fP \fIvariable\fP [ \fIvalue\fP ]
  819. XSet a boolean variable to true or assign the value to a string or
  820. Xinteger variable.  The
  821. X.B :set
  822. Xcommand is described in details in the section on VARIABLES.
  823. X.TP
  824. X\fB:sh\fP
  825. XSuspend \fInn\fP, or if that is not possible, spawn an interactive shell.
  826. X.TP
  827. X\fB:show groups\fP \fImode\fP
  828. XShow the total number or the number of unread articles in the current
  829. Xgroup, depending on \fImode\fP: \fBall\fP (list the number of unread
  830. Xarticles in all groups including groups which you have unsubscribed
  831. Xto), \fBtotal\fP (list the total number of articles in all existing
  832. Xgroups), \fBunsub\fP (list unsubscribed groups only).  Any other
  833. X\fImode\fP results in a listing of the number of unread articles in
  834. Xall subscribed groups including those you have suppressed with the `!'
  835. Xsymbol in the group presentation sequence.  To get just the currently
  836. Xunread groups in the presentation sequence, use the `Y'
  837. X{\fBoverview\fP} command.
  838. X.TP
  839. X\fB:show kill\fP
  840. XShow the kill entries that applies to the current group and to all groups.
  841. X.TP
  842. X\fB:show rc\fP [ \fIgroup\fP ]
  843. XShow the .newsrc and select file entries for the current or the
  844. Xspecified group.
  845. X.TP
  846. X\fB:show map\fP [ \fImode\fP ]
  847. XShow the key bindings in the current or specified mode.
  848. X.TP
  849. X\fB:sort\fP [ \fImode\fP ]
  850. XReorder the articles on the menu according to \fImode\fP or if omitted
  851. Xto the default \fBsort-mode\fP.  The following sorting modes are
  852. Xavailable: \fBarrival\fP (list articles in the order in which they
  853. Xarrived on the system), \fBsubject\fP (articles with identical
  854. Xsubjects are grouped and ordered after age of the oldest article in
  855. Xthe group), lexical (subjects in lexicographical order), \fBage\fP
  856. X(articles ordered after posting date only), and \fBsender\fP (articles
  857. Xordered after sender's name).
  858. X.TP
  859. X\fB:unset\fP \fIvariable\fP
  860. XToggle a boolean variable.
  861. X.TP
  862. X\fB:unread\fP [ \fIgroup\fP ] [ \fIarticles\fP ]
  863. XMark the current (or specified) group as unread.  If the
  864. X\fIarticles\fP argument is omitted, the number of unread articles in
  865. Xthe group will be set to the number of unread articles when \fInn\fP
  866. Xwas invoked.  Otherwise, the argument specifies the number of unread
  867. Xarticles.
  868. X.TP
  869. X\fB:unset\fP \fIvariable\fP
  870. XSet a boolean variable to false or clear an integer variable.
  871. X.TP
  872. X\fB:x\fP
  873. XQuit \fInn\fP and \fBmark\fP all articles in the current group as
  874. X\fIread\fP!
  875. X.LP
  876. X\fBRelated variables\fP:
  877. Xbackup, bug-report-address, delayed-redraw, keep-unsubscribed,
  878. Xunsubscribe-mark-read, mail, pager, sort-mode.
  879. X.\" ENDPART B
  880. END_OF_FILE
  881.   if test 32572 -ne `wc -c <'man/nn.1.B'`; then
  882.     echo shar: \"'man/nn.1.B'\" unpacked with wrong size!
  883.   fi
  884.   # end of 'man/nn.1.B'
  885. fi
  886. if test -f 'master.c' -a "${1}" != "-c" ; then 
  887.   echo shar: Will not clobber existing file \"'master.c'\"
  888. else
  889.   echo shar: Extracting \"'master.c'\" \(19338 characters\)
  890.   sed "s/^X//" >'master.c' <<'END_OF_FILE'
  891. X/*
  892. X *    (c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
  893. X *
  894. X *    nn database daemon (nnmaster)
  895. X *
  896. X *    maintains the article header database.
  897. X */
  898. X
  899. X#include <signal.h>
  900. X#include <errno.h>
  901. X#include "config.h"
  902. X#include "db.h"
  903. X#include "proto.h"
  904. X
  905. Ximport char *bin_directory;
  906. X
  907. X/*
  908. X * nnmaster options:
  909. X *
  910. X *    -e [N]    expire a group if more than N articles are gone
  911. X *    -r N    repeat every N minutes
  912. X *
  913. X *    -f    foreground execution (use with -r)
  914. X *    -y N    retry N times on error
  915. X *
  916. X *    -E [N]    expire mode (see expire.c) [N==1 if omitted]
  917. X *    -F    Run ONLY expire ONCE and exit.
  918. X *    -R N    auto-recollect mode (see expire.c)
  919. X *
  920. X *    -C    check consistency of database on start-up
  921. X *    -b    include 'bad' articles (disables -B)
  922. X *    -B    remove 'bad' articles (just unlink the files)
  923. X *    -O N    Consider articles older than N days as bad articles.
  924. X *
  925. X *    -I [N]    initialize [ limit to N articles in each group ]
  926. X *    -G    reread groups file.
  927. X *    -X    clean ignored groups.
  928. X *
  929. X *    -l"MSG"    lock database with message MSG
  930. X *    -l    unlock database
  931. X *    -i    ignore lock (run collection on locked database)
  932. X *    -k    kill the running master and take over.
  933. X *
  934. X *    -Q    quiet: don't write fatal errors to /dev/console (if no syslog).
  935. X *    -t    trace collection of each group
  936. X *    -v    print version and exit
  937. X *    -u    update even if active is not modified
  938. X *    -w    send wakeup to real master
  939. X *    -Ltypes    exclude 'types' entries from the log
  940. X *    -D [N]    debug, N = +(1 => verbose, 2 => nntp trace)
  941. X *
  942. X *    [master group]...    Collect these groups only.
  943. X */
  944. X
  945. X#include "options.h"
  946. X
  947. X
  948. Ximport int
  949. X    dont_write_console,
  950. X    expire_method,
  951. X    expire_level,
  952. X    recollect_method,
  953. X    reread_groups_file,
  954. X    ignore_bad_articles,
  955. X#ifdef NNTP
  956. X    nntp_local_server,
  957. X    nntp_debug,
  958. X#endif
  959. X    remove_bad_articles,
  960. X    retry_on_error;
  961. X
  962. Ximport time_t
  963. X    max_article_age;
  964. X
  965. Ximport char
  966. X    *log_entry_filter;
  967. X
  968. Xexport int
  969. X    trace = 0,
  970. X    debug_mode = 0,
  971. X#ifdef NNTP
  972. X    silent = 1,
  973. X    no_update = 0,
  974. X#endif
  975. X    Debug = 0;
  976. X
  977. Xstatic int
  978. X    check_on_startup = 0,
  979. X    clean_ignored = 0,
  980. X    expire_once = 0,
  981. X    foreground = 0,
  982. X    ignore_lock = 0,
  983. X    initialize = -1,
  984. X    kill_running = 0,
  985. X    max_age_days = 0,
  986. X    prt_vers = 0,
  987. X    unconditional = 0,
  988. X    wakeup_master = 0;
  989. X
  990. Xstatic unsigned
  991. X    repeat_delay = 0;
  992. X
  993. X
  994. Xstatic char
  995. X    *lock_message = NULL;
  996. X
  997. X
  998. XOption_Description(master_options) {
  999. X
  1000. X    'b', Bool_Option( ignore_bad_articles ),
  1001. X    'B', Bool_Option( remove_bad_articles ),
  1002. X    'C', Bool_Option( check_on_startup ),
  1003. X    'D', Int_Option_Optional( debug_mode, 1 ),
  1004. X    'e', Int_Option_Optional( expire_level, 1 ),
  1005. X    'E', Int_Option_Optional( expire_method, 1 ),
  1006. X    'f', Bool_Option( foreground ),
  1007. X    'F', Bool_Option( expire_once ),
  1008. X    'G', Bool_Option( reread_groups_file ),
  1009. X#ifdef NNTP
  1010. X    'H', Bool_Option( nntp_local_server ),
  1011. X#endif
  1012. X    'i', Bool_Option( ignore_lock ),
  1013. X    'I', Int_Option_Optional( initialize, 0 ),
  1014. X    'k', Bool_Option( kill_running ),
  1015. X    'l', String_Option_Optional( lock_message, "" ),
  1016. X    'L', String_Option( log_entry_filter ),
  1017. X    'O', Int_Option( max_age_days ),
  1018. X    'Q', Bool_Option( dont_write_console ),
  1019. X    'r', Int_Option_Optional( repeat_delay, 10 ),
  1020. X    'R', Int_Option( recollect_method ),
  1021. X    't', Bool_Option( trace ),
  1022. X    'u', Bool_Option( unconditional ),
  1023. X    'v', Bool_Option( prt_vers ),
  1024. X    'w', Bool_Option( wakeup_master ),
  1025. X    'X', Bool_Option( clean_ignored ),
  1026. X    'y', Int_Option( retry_on_error ),
  1027. X    '\0',
  1028. X};
  1029. X
  1030. Ximport char *master_directory, *db_directory, *news_active;
  1031. X
  1032. Xstatic int unlock_on_exit = 0;
  1033. X
  1034. X/*
  1035. X * nn_exit() --- called whenever a program exits.
  1036. X */
  1037. X
  1038. Xnn_exit(n)
  1039. X{
  1040. X#ifdef NNTP
  1041. X    if (use_nntp) nntp_cleanup();
  1042. X#endif /* NNTP */
  1043. X    close_master();
  1044. X
  1045. X    if (unlock_on_exit)
  1046. X    proto_lock(I_AM_MASTER, PL_CLEAR);
  1047. X
  1048. X    if (n)
  1049. X    log_entry('E', "Abnormal termination, exit=%d", n);
  1050. X    else
  1051. X    if (unlock_on_exit)
  1052. X    log_entry('M', "Master terminated%s", s_hangup ? " (hangup)" : "");
  1053. X
  1054. X    exit(n);
  1055. X}
  1056. X
  1057. X
  1058. Xstatic clean_group_internal(gh)    /* no write */
  1059. Xregister group_header *gh;
  1060. X{
  1061. X    gh->first_db_article = 0;
  1062. X    gh->last_db_article = 0;
  1063. X
  1064. X    if (gh->data_write_offset > (off_t)0) {
  1065. X    gh->data_write_offset = (off_t)0;
  1066. X    (void)open_data_file(gh, 'd', -1);
  1067. X    }
  1068. X    
  1069. X    if (gh->index_write_offset) {
  1070. X    gh->index_write_offset = (off_t)0;
  1071. X    (void)open_data_file(gh, 'x', -1);
  1072. X    }
  1073. X    
  1074. X    gh->master_flag &= ~(M_EXPIRE | M_BLOCKED);
  1075. X    if ((gh->master_flag & M_IGNORE_GROUP) == 0)
  1076. X    gh->master_flag |= M_BLOCKED;
  1077. X
  1078. X}
  1079. X
  1080. Xclean_group(gh)    /* does write */
  1081. Xgroup_header *gh;
  1082. X{
  1083. X    if (trace)
  1084. X    log_entry('T', "CLEAN %s", gh->group_name);
  1085. X    if (debug_mode)
  1086. X    printf("CLEAN %s\n", gh->group_name);
  1087. X
  1088. X    clean_group_internal(gh);
  1089. X
  1090. X    db_write_group(gh);
  1091. X}
  1092. X
  1093. Xextern long collect_group();
  1094. Xextern long expire_group();
  1095. X
  1096. Xstatic char **restrictions = NULL;
  1097. Xstatic int *restr_len, *restr_excl;
  1098. X
  1099. Xstatic group_restriction(gh)
  1100. Xregister group_header *gh;
  1101. X{
  1102. X    register char **rp;
  1103. X    register int *lp, *xp;
  1104. X
  1105. X    if (restrictions == NULL) return;
  1106. X
  1107. X    for (rp = restrictions, lp = restr_len, xp = restr_excl; *lp > 0; rp++, lp++, xp++)
  1108. X    if (strncmp(gh->group_name, *rp, *lp) == 0) {
  1109. X        if (*xp) break;
  1110. X        return;
  1111. X    }
  1112. X
  1113. X    if (*lp == 0) return;
  1114. X
  1115. X    gh->master_flag |= M_IGNORE_G;
  1116. X}
  1117. X
  1118. Xstatic set_group_restrictions(restr, n)
  1119. Xchar **restr;
  1120. Xint n;
  1121. X{
  1122. X    register group_header *gh;
  1123. X    register int i;
  1124. X
  1125. X    restrictions = restr;
  1126. X    restr_len = newobj(int, n + 1);
  1127. X    restr_excl = newobj(int, n);
  1128. X
  1129. X    for (i = 0; i < n; i++) {
  1130. X    if (restrictions[i][0] == '!') {
  1131. X        restr_excl[i] = 1;
  1132. X        restrictions[i]++;
  1133. X    } else
  1134. X        restr_excl[i] = 0;
  1135. X    restr_len[i] = strlen(restrictions[i]);
  1136. X    }
  1137. X
  1138. X    restr_len[n] = -1;
  1139. X
  1140. X    Loop_Groups_Header(gh) {
  1141. X    if (gh->master_flag & M_IGNORE_GROUP) continue;
  1142. X    group_restriction(gh);
  1143. X    if (clean_ignored && (gh->master_flag & M_IGNORE_G)) {
  1144. X        log_entry('X', "Group %s ignored", gh->group_name);
  1145. X        clean_group(gh);
  1146. X    }
  1147. X    }
  1148. X}
  1149. X
  1150. X/*
  1151. X * add new group to master file
  1152. X */
  1153. X
  1154. Xgroup_header *add_new_group(name)
  1155. Xchar *name;
  1156. X{
  1157. X    register group_header *gh;
  1158. X
  1159. X    if (master.free_groups <= 0)
  1160. X    db_expand_master();
  1161. X
  1162. X    master.free_groups--;
  1163. X
  1164. X    gh = &active_groups[master.number_of_groups];
  1165. X
  1166. X    gh->group_name_length = strlen(name);
  1167. X    gh->group_name = copy_str(name);
  1168. X
  1169. X    gh->group_num = master.number_of_groups++;
  1170. X    gh->creation_time = cur_time();
  1171. X
  1172. X    db_append_group(gh);
  1173. X
  1174. X    group_restriction(gh);    /* done after append to avoid setting ! */
  1175. X    clean_group(gh);
  1176. X
  1177. X    db_write_master();
  1178. X
  1179. X    sort_groups();
  1180. X
  1181. X    log_entry('C', "new group: %s (%d)", gh->group_name, gh->group_num);
  1182. X
  1183. X    return gh;
  1184. X}
  1185. X
  1186. X
  1187. Xstatic visit_active_file()
  1188. X{
  1189. X    FILE *act;
  1190. X    FILE *nntp_act = NULL;
  1191. X
  1192. X#ifdef NNTP
  1193. X    if (!use_nntp)        /* copy 'active' to DB/ACTIVE */
  1194. X    nntp_act = open_file(relative(db_directory, "ACTIVE"), OPEN_CREATE | MUST_EXIST);
  1195. X#endif
  1196. X
  1197. X    act = open_file(news_active, OPEN_READ|MUST_EXIST);
  1198. X
  1199. X    read_active_file(act, nntp_act);
  1200. X
  1201. X    master.last_size = ftell(act);
  1202. X
  1203. X    fclose(act);
  1204. X
  1205. X#ifdef NNTP
  1206. X    if (nntp_act != NULL) fclose(nntp_act);
  1207. X#endif
  1208. X}
  1209. X
  1210. X
  1211. X/*
  1212. X *    Build initial master file.
  1213. X */
  1214. X
  1215. Xstatic build_master()
  1216. X{
  1217. X    char command[512];
  1218. X    char groupname[512];
  1219. X    group_header *groups, *next_g, *gh;
  1220. X    FILE *src;
  1221. X    int lcount, use_group_file, found_nn_group = 0;
  1222. X
  1223. X    printf("Confirm initialization by typing 'OK': ");
  1224. X    fl;
  1225. X    gets(command);
  1226. X    if (strcmp(command, "OK")) {
  1227. X    printf("No initialization\n");
  1228. X    nn_exit(0);
  1229. X    }
  1230. X
  1231. X    if (chdir(master_directory) < 0)    /* so we can use open_file (?) */
  1232. X    sys_error("master");
  1233. X
  1234. X#ifdef NNTP
  1235. X    if (use_nntp && nntp_get_active() < 0)
  1236. X        sys_error("Can't get active file");
  1237. X#endif
  1238. X    /* check active file for duplicates */
  1239. X
  1240. X    sprintf(command, "awk 'NF>0{print $1}' %s | sort | uniq -d", news_active);
  1241. X
  1242. X    src = popen(command, "r");
  1243. X    if (src == NULL)
  1244. X    sys_error("popen(%s) failed", command);
  1245. X    
  1246. X    for (lcount = 0; fgets(groupname, 512, src); lcount++) {
  1247. X    if (lcount == 0)
  1248. X        printf("\n%s contains duplicate entries for the following groups:",
  1249. X           news_active);
  1250. X
  1251. X    fputs(groupname, stdout);
  1252. X    }
  1253. X
  1254. X    pclose(src);
  1255. X
  1256. X    if (lcount > 0) {
  1257. X    printf("Do you want to repair this file before continuing ? (y)");
  1258. X    gets(command);
  1259. X    if (s_hangup ||
  1260. X        command[0] == NUL || command[0] == 'y' || command[0] == 'Y')
  1261. X        nn_exit(0);
  1262. X    }
  1263. X
  1264. X    /* if a "GROUPS" file exist offer to use that, else */
  1265. X    /* read group names from active file */
  1266. X
  1267. X    use_group_file = 0;
  1268. X
  1269. X    if (open_groups(OPEN_READ)) {
  1270. X    printf("\nA GROUPS file already exist -- reuse it? (y)");
  1271. X    fl;
  1272. X    gets(command);
  1273. X    if (command[0] == NUL || command[0] == 'y' || command[0] == 'Y') {
  1274. X        use_group_file = 1;
  1275. X    } else
  1276. X        close_groups();
  1277. X    if (s_hangup) return;
  1278. X    }
  1279. X
  1280. X    printf("\nBuilding %s/MASTER file\n", db_directory);
  1281. X    fl;
  1282. X
  1283. X    if (!use_group_file) {
  1284. X    sprintf(command, "awk 'NF>0{print $1}' %s | sort -u", news_active);
  1285. X
  1286. X    src = popen(command, "r");
  1287. X    if (src == NULL)
  1288. X        sys_error("popen(%s) failed", command);
  1289. X    }
  1290. X
  1291. X    open_master(OPEN_CREATE);
  1292. X
  1293. X    master.db_magic = NNDB_MAGIC;
  1294. X    master.last_scan = 0;
  1295. X    master.number_of_groups = 0;
  1296. X    strcpy(master.db_lock, "Initializing database");
  1297. X
  1298. X    db_write_master();
  1299. X
  1300. X    groups = next_g = newobj(group_header, 1);
  1301. X    next_g->next_group = NULL;
  1302. X
  1303. X    for (;;) {
  1304. X    if (s_hangup) goto intr;
  1305. X    gh = newobj(group_header, 1);
  1306. X
  1307. X    gh->master_flag = 0;
  1308. X
  1309. X    if (use_group_file) {
  1310. X        gh->group_name_length = 0;
  1311. X        if (db_parse_group(gh, 0) <= 0) break;
  1312. X    } else {
  1313. X        if (fgets(groupname, 512, src) == NULL) break;
  1314. X
  1315. X        gh->group_name_length = strlen(groupname) - 1;    /* strip NL */
  1316. X        groupname[gh->group_name_length] = NUL;
  1317. X        gh->creation_time = 0;
  1318. X        gh->group_name = copy_str(groupname);
  1319. X        gh->archive_file = NULL;
  1320. X    }
  1321. X
  1322. X    gh->group_num = master.number_of_groups++;
  1323. X
  1324. X    if (trace || debug_mode)
  1325. X        printf("%4d '%s' (%d)\n", gh->group_num, gh->group_name,
  1326. X           gh->group_name_length);
  1327. X
  1328. X    next_g->next_group = gh;
  1329. X    next_g = gh;
  1330. X    gh->next_group = NULL;
  1331. X
  1332. X    init_group(gh);    /* for clean_group() */
  1333. X
  1334. X    /* moderation flag will be set by first visit_active_file call */
  1335. X
  1336. X    if (strcmp(gh->group_name, "control") == 0)
  1337. X        gh->master_flag |= M_CONTROL;
  1338. X
  1339. X    if (strcmp(gh->group_name, "news.software.nn") == 0)
  1340. X        found_nn_group++;
  1341. X
  1342. X    gh->master_flag &= ~M_MUST_CLEAN;
  1343. X    clean_group_internal(gh);
  1344. X    gh->master_flag |= M_VALID;    /* better than the reverse */
  1345. X    db_write_group(gh);
  1346. X    }
  1347. X
  1348. X    if (use_group_file)
  1349. X    close_groups();
  1350. X    else
  1351. X    pclose(src);
  1352. X
  1353. X    printf("%s %s/GROUPS file\n",
  1354. X       use_group_file ? "Updating" : "Building", db_directory);
  1355. X    sprintf(command, "cd %s ; [ -f GROUPS ] && (rm -f GROUPS~ ; mv GROUPS GROUPS~)",
  1356. X        db_directory);
  1357. X    system(command);
  1358. X
  1359. X    open_groups(OPEN_CREATE|MUST_EXIST);
  1360. X
  1361. X    for (gh = groups->next_group; gh != NULL; gh = gh->next_group)
  1362. X    db_append_group(gh);
  1363. X
  1364. X    close_groups();
  1365. X
  1366. X    if (initialize > 0) {
  1367. X    printf("Setting articles per group limit to %d...\n", initialize);
  1368. X    db_write_master();
  1369. X    open_master(OPEN_READ);
  1370. X    open_master(OPEN_UPDATE);
  1371. X    visit_active_file();
  1372. X    Loop_Groups_Header(gh) {
  1373. X        gh->first_db_article = gh->last_a_article - initialize + 1;
  1374. X        if (gh->first_db_article <= gh->first_a_article) continue;
  1375. X        gh->last_db_article = gh->first_db_article - 1;
  1376. X        if (gh->last_db_article < 0) gh->last_db_article = 0;
  1377. X        db_write_group(gh);
  1378. X    }
  1379. X    }
  1380. X    
  1381. X    master.db_lock[0] = NUL;
  1382. X    master.db_created = cur_time();
  1383. X
  1384. X    db_write_master();
  1385. X
  1386. X    close_master();
  1387. X
  1388. X    printf("Done\n");
  1389. X    fl;
  1390. X
  1391. X    log_entry('M', "Master data base initialized");
  1392. X
  1393. X    if (!found_nn_group)
  1394. X    printf("\nNotice: nn's own news group `news.software.nn' was not found\n");
  1395. X
  1396. X    return;
  1397. X
  1398. X intr:
  1399. X    printf("\nINTERRUPT\n\nDatabase NOT completed\n");
  1400. X    log_entry('M', "Master data base initialization not completed (INTERRUPTED)");
  1401. X}
  1402. X
  1403. Xstatic set_lock_message()
  1404. X{
  1405. X    open_master(OPEN_UPDATE);
  1406. X    db_read_master();
  1407. X    if (lock_message[0] || master.db_lock[0]) {
  1408. X    strncpy(master.db_lock, lock_message, DB_LOCK_MESSAGE);
  1409. X    master.db_lock[DB_LOCK_MESSAGE-1] = NUL;
  1410. X    db_write_master();
  1411. X    printf("DATABASE %sLOCKED\n", lock_message[0] ? "" : "UN");
  1412. X    }
  1413. X}
  1414. X
  1415. Xstatic do_reread_groups()
  1416. X{
  1417. X    register group_header *gh;
  1418. X
  1419. X    open_master(OPEN_UPDATE);
  1420. X    Loop_Groups_Header(gh)
  1421. X    if (gh->master_flag & M_MUST_CLEAN) {
  1422. X        gh->master_flag &= ~M_MUST_CLEAN;
  1423. X        clean_group(gh);
  1424. X    } else
  1425. X        db_write_group(gh);
  1426. X    master.last_scan = 0;
  1427. X    db_write_master();
  1428. X    close_master();
  1429. X    log_entry('M', "Reread GROUPS file");
  1430. X}
  1431. X
  1432. X
  1433. Xmain(argc, argv)
  1434. Xint argc;
  1435. Xchar **argv;
  1436. X{
  1437. X    register group_header *gh;
  1438. X    time_t age_active;
  1439. X    int group_selection;
  1440. X    int temp;
  1441. X
  1442. X    umask(002);            /* avoid paranoia */
  1443. X
  1444. X    who_am_i = I_AM_MASTER;
  1445. X
  1446. X    init_global();
  1447. X
  1448. X    group_selection =
  1449. X    parse_options(argc, argv, (char *)NULL, master_options, (char *)NULL);
  1450. X
  1451. X    if (debug_mode) {
  1452. X#ifdef NNTP
  1453. X    nntp_debug = debug_mode & 2;
  1454. X#endif
  1455. X    debug_mode = debug_mode & 1;
  1456. X    }
  1457. X
  1458. X    if (debug_mode) {
  1459. X    extern sig_type catch_hangup();
  1460. X    signal(SIGINT, catch_hangup);
  1461. X    }
  1462. X
  1463. X    if (wakeup_master) {
  1464. X    if (proto_lock(I_AM_MASTER, PL_WAKEUP) < 0)
  1465. X        printf("master is not running\n");
  1466. X    exit(0);
  1467. X    }
  1468. X
  1469. X    if (prt_vers) {
  1470. X    printf("nnmaster release %s\n", version_id);
  1471. X    exit(0);
  1472. X    }
  1473. X
  1474. X    if (kill_running) {
  1475. X    for (temp = 10; --temp >= 0; sleep(3))
  1476. X        if (proto_lock(I_AM_MASTER, PL_TERMINATE) < 0) break;
  1477. X
  1478. X    if (temp < 0) {
  1479. X        printf("The running master will not die....!\n");
  1480. X        log_entry('E', "Could not kill running master");
  1481. X        exit(1);
  1482. X    }
  1483. X
  1484. X    if (repeat_delay == 0 && !foreground &&
  1485. X        !reread_groups_file && lock_message == NULL &&
  1486. X        group_selection == 0 && initialize < 0)
  1487. X        exit(0);
  1488. X    }
  1489. X
  1490. X    if (proto_lock(I_AM_MASTER, PL_SET) != 0) {
  1491. X    printf("The master is already running\n");
  1492. X    exit(0);
  1493. X    }
  1494. X    unlock_on_exit = 1;
  1495. X
  1496. X#ifdef NNTP
  1497. X    nntp_check();
  1498. X#endif
  1499. X
  1500. X    if (initialize >= 0) {
  1501. X    build_master();
  1502. X    nn_exit(0);
  1503. X    }
  1504. X
  1505. X    if (lock_message != NULL) {
  1506. X    set_lock_message();
  1507. X    if (repeat_delay == 0 && !foreground &&
  1508. X        !reread_groups_file && group_selection == 0)
  1509. X        nn_exit(0);
  1510. X    }
  1511. X
  1512. X    open_master(OPEN_READ);
  1513. X
  1514. X    if (!ignore_lock && master.db_lock[0]) {
  1515. X    printf("Database locked (unlock with -l or ignore with -i)\n");
  1516. X    nn_exit(88);
  1517. X    }
  1518. X
  1519. X    if (reread_groups_file) {
  1520. X    do_reread_groups();
  1521. X    nn_exit(0);
  1522. X    }
  1523. X
  1524. X    if (!debug_mode) {
  1525. X    close(0);
  1526. X    close(1);
  1527. X    close(2);
  1528. X    if (open("/dev/null", 2) == 0) dup(0), dup(0);
  1529. X    }
  1530. X
  1531. X    if (repeat_delay && !debug_mode && !foreground) {
  1532. X    while ((temp = fork()) < 0) sleep(1);
  1533. X    if (temp) exit(0);    /* not nn_exit() !!! */
  1534. X
  1535. X    process_id = getpid();    /* init_global saved parent's pid */
  1536. X
  1537. X    proto_lock(I_AM_MASTER, PL_TRANSFER);
  1538. X
  1539. X#ifdef DETATCH_TERMINAL
  1540. X    DETATCH_TERMINAL
  1541. X#endif
  1542. X    }
  1543. X
  1544. X    log_entry('M', "Master started -r%d -e%d %s-E%d",
  1545. X          repeat_delay, expire_level,
  1546. X          expire_once ? "-F " : "", expire_method);
  1547. X
  1548. X    if (check_on_startup) {
  1549. X    char cmd[FILENAME];
  1550. X    sprintf(cmd, "%s/nnadmin Z", bin_directory);
  1551. X    system(cmd);
  1552. X    log_entry('M', "Database validation completed");
  1553. X    }
  1554. X
  1555. X    repeat_delay *= 60;
  1556. X
  1557. X    init_digest_parsing();
  1558. X
  1559. X    open_master(OPEN_UPDATE);
  1560. X
  1561. X    if (group_selection)
  1562. X    set_group_restrictions(argv + 1, group_selection);
  1563. X
  1564. X    if (max_age_days && !use_nntp) /* we have to stat spool files */
  1565. X    max_article_age = cur_time() - (time_t)max_age_days * 24 * 60 * 60;
  1566. X    else
  1567. X    max_article_age = 0;
  1568. X
  1569. X    if (expire_once) {
  1570. X    if (group_selection)    /* mark selected groups for expire */
  1571. X        Loop_Groups_Header(gh) {
  1572. X        if (gh->master_flag & M_IGNORE_GROUP) continue;
  1573. X        gh->master_flag |= M_EXPIRE;
  1574. X        }
  1575. X    unconditional = 1;
  1576. X    }
  1577. X
  1578. X    for (;;) {
  1579. X#ifdef NNTP
  1580. X    if (use_nntp && nntp_get_active() < 0) {
  1581. X        nntp_close_server();
  1582. X        current_group = NULL; /* for init_group */
  1583. X        log_entry('N', "Can't access active file --- %s",
  1584. X              repeat_delay ? "sleeping" : "terminating");
  1585. X        if (repeat_delay == 0)
  1586. X        nn_exit(1);
  1587. X        sleep(repeat_delay);
  1588. X        continue;
  1589. X    }
  1590. X#endif
  1591. X
  1592. X    age_active = file_exist(news_active, "fr");
  1593. X    if (!use_nntp && age_active == (time_t)0)
  1594. X        sys_error("Cannot access active file");
  1595. X
  1596. X    if (unconditional) {
  1597. X        master.last_scan = age_active - 60;
  1598. X        unconditional = 0;
  1599. X    }
  1600. X
  1601. X    if (!receive_admin() && age_active <= master.last_scan) {
  1602. X        if (repeat_delay == 0) break;
  1603. X        if (s_hangup) break;
  1604. X#ifdef NNTP
  1605. X        if (use_nntp) nntp_cleanup();
  1606. X#endif
  1607. X        if (debug_mode) {
  1608. X        printf("NONE (*** SLEEP ***)\n");
  1609. X        continue;
  1610. X        }
  1611. X
  1612. X        if (trace) log_entry('T', "none");
  1613. X        sleep(repeat_delay);
  1614. X        if (s_hangup) break;
  1615. X        continue;
  1616. X    }
  1617. X
  1618. X    visit_active_file();
  1619. X
  1620. X    if (do_expire())
  1621. X        if (!expire_once && do_collect())
  1622. X        master.last_scan = age_active;
  1623. X
  1624. X    db_write_master();
  1625. X
  1626. X    if (expire_once || s_hangup) break;
  1627. X    if (repeat_delay == 0) break;
  1628. X
  1629. X#ifdef NNTP
  1630. X    if (use_nntp) nntp_cleanup();
  1631. X#endif
  1632. X    if (!debug_mode) sleep(repeat_delay);
  1633. X    if (s_hangup) break;
  1634. X    }
  1635. X
  1636. X    nn_exit(0);
  1637. X    /*NOTREACHED*/
  1638. X}
  1639. X
  1640. X
  1641. X
  1642. X/*
  1643. X * receive commands from administrator
  1644. X */
  1645. X
  1646. Xreceive_admin()
  1647. X{
  1648. X    FILE *gate;
  1649. X    char buffer[128], *bp;
  1650. X    char command, opt, *user_date;
  1651. X    int32 arg;
  1652. X    int must_collect;
  1653. X    register group_header *gh;
  1654. X
  1655. X    gate = open_file(relative(master_directory, "GATE"), OPEN_READ | OPEN_UNLINK);
  1656. X    if (gate == NULL) return 0;
  1657. X
  1658. X    sleep(2);    /* give administrator time to flush buffers */
  1659. X
  1660. X    must_collect = 0;
  1661. X
  1662. X    while (fgets(buffer, 128, gate)) {
  1663. X    bp = buffer;
  1664. X
  1665. X    command = *bp++;
  1666. X    if (*bp++ != ';') continue;
  1667. X
  1668. X    arg = atol(bp);
  1669. X    if (arg >= master.number_of_groups) continue;
  1670. X    gh = (arg >= 0) ? &active_groups[arg] : NULL;
  1671. X    if ((bp = strchr(bp, ';')) == NULL) continue;
  1672. X    bp++;
  1673. X
  1674. X    opt = *bp++;
  1675. X    if (*bp++ != ';') continue;
  1676. X
  1677. X    arg = atol(bp);
  1678. X    if ((bp = strchr(bp, ';')) == NULL) continue;
  1679. X
  1680. X    user_date = ++bp;
  1681. X    if ((bp = strchr(bp, ';')) == NULL) continue;
  1682. X    *bp++ = NUL;
  1683. X    if (*bp != NL) continue;
  1684. X
  1685. X    log_entry('A', "RECV %c %s %c %ld (%s)",
  1686. X          command, gh == NULL ? "(all)" : gh->group_name, opt, arg, user_date);
  1687. X
  1688. X    switch (command) {
  1689. X
  1690. X     case SM_SET_OPTION:
  1691. X        switch (opt){
  1692. X         case 'r':
  1693. X        repeat_delay = arg;
  1694. X        continue;
  1695. X         case 'e':
  1696. X        expire_level = arg;
  1697. X        continue;
  1698. X         case 't':
  1699. X        trace = (arg < 0) ? !trace : arg;
  1700. X        continue;
  1701. X        }
  1702. X
  1703. X     case SM_EXPIRE:
  1704. X        if (gh) {
  1705. X        gh->master_flag |= M_EXPIRE | M_BLOCKED;
  1706. X        db_write_group(gh);
  1707. X        break;
  1708. X        }
  1709. X        Loop_Groups_Header(gh) {
  1710. X        if (gh->master_flag & M_IGNORE_GROUP) continue;
  1711. X        if (gh->index_write_offset == 0) continue;
  1712. X        if (gh->master_flag & M_EXPIRE) continue;
  1713. X        gh->master_flag |= M_EXPIRE;
  1714. X        db_write_group(gh);
  1715. X        }
  1716. X        break;
  1717. X
  1718. X     case SM_SET_FLAG:
  1719. X        if (opt == 's')
  1720. X        gh->master_flag |= (flag_type)arg;
  1721. X        else
  1722. X        gh->master_flag &= ~(flag_type)arg;
  1723. X        db_write_group(gh);
  1724. X        continue;
  1725. X
  1726. X     case SM_RECOLLECT:    /* recollect */
  1727. X        if (gh) {
  1728. X        if ((gh->master_flag & M_IGNORE_GROUP) == 0)
  1729. X            clean_group(gh);
  1730. X        } else
  1731. X        Loop_Groups_Header(gh)
  1732. X            if ((gh->master_flag & M_IGNORE_GROUP) == 0)
  1733. X            clean_group(gh);
  1734. X        break;
  1735. X
  1736. X     case SM_SCAN_ONCE:    /* unconditional pass */
  1737. X        unconditional++;
  1738. X        break;
  1739. X
  1740. X     default:
  1741. X        continue;
  1742. X    }
  1743. X    must_collect = 1;
  1744. X    }
  1745. X
  1746. X    fclose(gate);
  1747. X
  1748. X    return must_collect;
  1749. X}
  1750. X
  1751. X
  1752. Xwrite_error()
  1753. X{
  1754. X    /*
  1755. X     * should wait for problems to clear out rather than die...
  1756. X     */
  1757. X    sys_error("DISK WRITE ERROR");
  1758. X}
  1759. X
  1760. X/*
  1761. X * dummy routines - should never be called by master
  1762. X */
  1763. X
  1764. X/*VARARGS*/
  1765. Xuser_error()
  1766. X{
  1767. X    dummy_error("user_error");
  1768. X}
  1769. X
  1770. Xdummy_error(name)
  1771. Xchar *name;
  1772. X{
  1773. X    sys_error("Dummy routine called by master: %s", name);
  1774. X}
  1775. X
  1776. X#ifdef HAVE_JOBCONTROL
  1777. Xsuspend_nn()
  1778. X{}
  1779. X#endif
  1780. X
  1781. X#ifdef NNTP /* XXX */
  1782. X/*VARARGS*/
  1783. Xmsg() {}
  1784. Xuser_delay(n) {}
  1785. X#endif /* NNTP Bogus */
  1786. END_OF_FILE
  1787.   if test 19338 -ne `wc -c <'master.c'`; then
  1788.     echo shar: \"'master.c'\" unpacked with wrong size!
  1789.   fi
  1790.   # end of 'master.c'
  1791. fi
  1792. echo shar: End of archive 7 \(of 22\).
  1793. cp /dev/null ark7isdone
  1794. MISSING=""
  1795. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ; do
  1796.     if test ! -f ark${I}isdone ; then
  1797.     MISSING="${MISSING} ${I}"
  1798.     fi
  1799. done
  1800. if test "${MISSING}" = "" ; then
  1801.     echo You have unpacked all 22 archives.
  1802.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1803. else
  1804.     echo You still must unpack the following archives:
  1805.     echo "        " ${MISSING}
  1806. fi
  1807. exit 0
  1808.  
  1809. exit 0 # Just in case...
  1810.